Add Todo


//todo Reducer
const todo = (state, action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return {
          id: action.id,
          text: action.text,
          completed: false
        };
    case 'TOGGLE_TODO':
      if (state.id !== action.id) {
        return state;
      }

      return {
        ...state,
        completed: !state.completed
      };
    default:
      return state;
  }
};
//todos Reducer
const todos = (state = [], action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        todo(undefined, action)
      ];
    case 'TOGGLE_TODO':
      return state.map(t => todo(t, action));
    default:
      return state;
  }
};

const visibilityFilter = (state = 'SHOW_ALL',
  action) => {
  switch (action.type) {
    case 'SET_VISIBILITY_FILTER':
      return action.filter;
    default:
      return state;      
  }
};


let nextTodoId = 0;
const { createStore, combineReducers } = Redux;

const todoApp = combineReducers({todos,visibilityFilter});
const store = createStore(todoApp);

const { Component } = React;

class TodoApp extends Component {
  render() {
    return (
      <div>
        <input ref={node => {
          this.input = node;
      }} />
        <button onClick={() => {
          store.dispatch({
            type: 'ADD_TODO',
            text: this.input.value,
            id: nextTodoId++
          });
         }}>
           Add Todo
         </button>
         <ul>
           {this.props.todos.map(todo => 
             <li key={todo.id}>
               {todo.text}
             </li>
           )}
         </ul>
      </div>
    );
  };
};

const render = () => {
  ReactDOM.render(
    <TodoApp todos={store.getState().todos} />,
    document.getElementById('root')
  );
};

store.subscribe(render);
render();

//最终代码: http://jsbin.com/zulokux/edit?js,output

Toggling a Todo

<li key={todo.id} >
    {todo.text}
</li>
//...*/

// 修改后
<li key={todo.id} 
    onClick={() =>{
      store.dispatch({
        type: 'TOGGLE_TODO',
        id: todo.id
      });
    }}
    style={{
           textDecoration:
           todo.completed ? 
             'line-through' : 'none'
          }}>
    {todo.text}
    </li>

Filtering Todos

Step1: 创建FiterLink控件


const { Component } = React;

const FilterLink = ({filter, children, currentFilter}) => {
  return (
    <a href='#'
      onClick={e => {
        e.preventDefault();
        store.dispatch({
          type: 'SET_VISIBILITY_FILTER',
          filter
        })
    }}>
      {children}
    </a>
  );
}

Step2: ul元素后面添加过滤功能

 <p>
Show: 
{' '}
<FilterLink filter='SHOW_ALL'>ALL</FilterLink>
{' '}
<FilterLink filter='SHOW_ACTIVE'>Active</FilterLink>
{' '}
<FilterLink filter='SHOW_COMPLETED'>Completed</FilterLink>
</p>

Step3: 过滤列表方法

const getVisibleTodos = (todos, filter) => {
  switch (filter){
    case 'SHOW_ALL':
      return todos;
    case 'SHOW_COMPLETED':
      return todos.filter(
        t => t.completed
      );
    case 'SHOW_ACTIVE':
      return todos.filter(
        t => !t.completed
      );   
  }       
}  

Step4: 显示过滤后的Todo列表


//     const visibleTodos = getVisibleTodos(
//       this.props.todos,
//       this.props.visibilityFilter
//     );

//es6写法
const { todos,visibilityFilter } = this.props;
const visibleTodos = getVisibleTodos(todos,visibilityFilter);
// <ul> {this.props.todos.map(...) 修改成visibleTodos
 <ul> {visibleTodos.map(...)
    <li ... >{todo.text}</li>
 </ul>

Step5:

//<TodoApp todos={store.getState().todos} />
<TodoApp {...store.getState()} />

Step6: 修改FilterLink单击后取消功能

每个FilterLink属性上添加 currentFilter={visibilityFilter}

//<FilterLink filter='SHOW_ACTIVE' >Active</FilterLink>
<FilterLink filter='SHOW_ACTIVE' currentFilter={visibilityFilter}>Active</FilterLink>
const FilterLink = ({filter, children, currentFilter}) => {
  if (filter === currentFilter){        //++
    return <span>{children}</span>;     //++
  }     //++
  return (
    <a href='#'
      onClick={e => {
        e.preventDefault();
        store.dispatch({
          type: 'SET_VISIBILITY_FILTER',
          filter
        });
    }}>
      {children}
    </a>
  );
}

//最终代码: http://jsbin.com/bogegih/edit?js,output